#include "stdafx.h"
#include "KnowledgeBase.h"
#include "GlobalData.h"
#include "KeyHandler.h"

BaseCodeAttr::BaseCodeAttr(CONST LPTSTR lpCode,INT freq,BOOL isword)
{
	this->frequency = freq;
	_tcscpy(this->baseCode,lpCode);
	this->isChineseWord = isword;
}
INT BaseCodeAttr::CompareTo(CONST BaseCodeAttr& baseCode) CONST
{
	if(this->isChineseWord > baseCode.isChineseWord)
		return 1;
	else if(this->isChineseWord == baseCode.isChineseWord)
	{
		if(this->frequency > baseCode.frequency)
			return 1;
		else if(this->frequency == baseCode.frequency)
			return _tcscmp(this->baseCode,baseCode.baseCode);
		else
			return - 1;
	}
	else
		return -1;
}
VOID BaseCodeAttr::CopyFrom(CONST BaseCodeAttr& baseCode)
{
	if(this == &baseCode)
		return;
	this->frequency = baseCode.frequency;
	_tcscpy(this->baseCode,baseCode.baseCode);
	this->isChineseWord = baseCode.isChineseWord;
}
LPTSTR BaseCodeAttr::GetCode()
{
	CONST LPTSTR p = this->baseCode;
	return p;
}
BOOL BaseCodeAttr::IsChineseWord() CONST
{
	return this->isChineseWord;
}
BaseCodeAttr::BaseCodeAttr(CONST BaseCodeAttr& baseCode)
{
	this->CopyFrom(baseCode);
}
BaseCodeAttr& BaseCodeAttr::operator=(CONST BaseCodeAttr& baseCode)
{
	this->CopyFrom(baseCode);
	return *this;
}
BOOL BaseCodeAttr::operator>(CONST BaseCodeAttr& baseCode) CONST
{
	return this->CompareTo(baseCode) > 0;
}
BOOL BaseCodeAttr::operator<(CONST BaseCodeAttr& baseCode) CONST
{
	return this->CompareTo(baseCode) < 0;
}
BOOL BaseCodeAttr::operator==(CONST BaseCodeAttr& baseCode) CONST
{
	return this->CompareTo(baseCode) == 0;
}
BOOL BaseCodeAttr::operator>=(CONST BaseCodeAttr& baseCode) CONST
{
	return !(*this < baseCode);
}
BOOL BaseCodeAttr::operator<=(CONST BaseCodeAttr& baseCode) CONST
{
	return !(*this > baseCode);
}
BOOL BaseCodeAttr::operator!=(CONST BaseCodeAttr& baseCode) CONST
{
	return !(*this == baseCode);
}

VOID KnowledgeProcess::GetBaseCode(CONST std::list<LPBYTE>& byteList,UINT fromPos,std::set<BaseCodeAttr,std::greater<BaseCodeAttr> >& result)
{
	TCHAR preCode[BASE_CODE_LEN] = _T("\0");
	UINT freq = 0;
	BOOL first = TRUE;
	
	for(std::list<LPBYTE>::const_iterator it = byteList.begin();it != byteList.end(); ++it)
	{		
		INT struct_flag = -1000000;
		TCHAR code[BASE_CODE_LEN];
		UINT index = 0;
		UINT pos = fromPos;
		CONST LPTSTR lpTxt = GetWordCode(*it);
		UINT len = _tcslen(lpTxt);
		if(pos >= len)
		{
			if(pos == len)
			{
				result.insert(BaseCodeAttr(GetWord(*it),GetFrequency(*it),1));
			}
			continue;
		}
		for(;;)
		{
			TCHAR c = *(lpTxt + pos++);
			if(pos == len + 1)
				break;
			if(c == ',')
			{
				if(index == 0)
					continue;
				else
					break;
			}
			code[index++] = c;
			if(index >= BASE_CODE_LEN)
				break;
		}
		if(index != 0)
		{
			code[index] = '\0';
			
			if(first)
			{
				_tcscpy(preCode,code);
				freq = GetFrequency(*it);
				first = FALSE;
				continue;
			}

			if(_tcscmp(code,preCode) == 0)
			{
				INT temp_frq = GetFrequency(*it);
				freq = freq > temp_frq ? freq : temp_frq;
				continue;
			}
			else
			{
				result.insert(BaseCodeAttr(preCode,freq,0));
				_tcscpy(preCode,code);
				freq = GetFrequency(*it);
				if(1 == index)
				{
					if(!(GlobalData::Setting & STRUCT_CODE_NORMAL))
						freq += struct_flag;
				}
				else
				{
					if(GlobalData::Setting & BASECODE_FREQ_FIRST)
						freq = GlobalData::GetInstance()->GetBaseFreq(code);
				}
			}
		}
	}
	if(_tcslen(preCode) > 0)
		result.insert(BaseCodeAttr(preCode,freq,0));
}

VOID KnowledgeProcess::KnowledgeFilter(CONST std::list<LPBYTE>& byteList,CONST LPTSTR lpTxt,TCHAR pinYin,std::list<LPBYTE>& result)
{
	BOOL beginFlag = FALSE;
	for(std::list<LPBYTE>::const_iterator it = byteList.begin(); it != byteList.end(); ++it)
	{
		if(pinYin && pinYin != GetPinyin(*it) && GetPinyin(*it) != _T('v'))
			continue;
		if(Str1BeginWithStr2(GetWordCode(*it),lpTxt))
		{
			beginFlag = TRUE;
			result.push_back(*it);
		}
		else
		{
			if(beginFlag)
				break;
		}
	}
}

UINT KnowledgeProcess::GetFrequency(CONST LPBYTE lpByte)
{
	return ((LPKNOWLEDGEIMMAP)lpByte)->frequency;
}
TCHAR KnowledgeProcess::GetPinyin(CONST LPBYTE lpByte)
{
	return ((LPKNOWLEDGEIMMAP)lpByte)->pinYin;
}
CONST LPTSTR KnowledgeProcess::GetWord(CONST LPBYTE lpByte)
{
	return ((LPKNOWLEDGEIMMAP)lpByte)->word;
}
CONST LPTSTR KnowledgeProcess::GetWordCode(CONST LPBYTE lpByte)
{
	return (LPTSTR)(lpByte + ((LPKNOWLEDGEIMMAP)lpByte)->dwCodeOffset);
}

BOOL KnowledgeProcess::Str1BeginWithStr2(CONST LPTSTR str1,CONST LPTSTR str2)
{
	LPTSTR lpstr1,lpstr2;
	lpstr1 = str1;
	lpstr2 = str2;
	while(TRUE)
	{
		if(*lpstr2 == '\0')
			return TRUE;
		if(*lpstr1 == '\0')
			return FALSE;
		if (*lpstr1 != *lpstr2)
			return FALSE;
		++lpstr1;
		++lpstr2;
	}
	return FALSE;
}

std::list<LPBYTE> KnowledgeProcess::preResult;
UINT KnowledgeProcess::preInputLen = 0;

KnowledgeProcess::KnowledgeProcess(ImmData* lpImmData)
{
	this->lpCodeList = GlobalData::GetInstance()->GetCodeList();
	this->lpImmData = lpImmData;
}

UINT KnowledgeProcess::TranslateInput()
{
	TCHAR pinYin = this->lpImmData->GetCompStrClass()->GetPinYin();
	CONST LPTSTR lpTxt = this->lpImmData->GetCompStrClass()->GetCompositionString();
	CONST std::list<LPBYTE>* lptempList = this->lpCodeList;
	if(this->lpImmData->GetCompStrClass()->GetInputLen() > preInputLen && preResult.size())
	{
		lptempList = &preResult;
	}
	std::list<LPBYTE> result;
	KnowledgeFilter(*lptempList,lpTxt,pinYin,result);
	preResult.clear();

	if(result.size() == 0)
		return 0;
	if(result.size() == 1)
	{
		this->lpImmData->GetCompStrClass()->SetResultString(GetWord(result.front()));
		return 1;
	}
	else
	{
		this->lpImmData->GetCompStrClass()->SetResultString(GetWord(result.front()));
		preInputLen = this->lpImmData->GetCompStrClass()->GetInputLen();
		preResult = result;
	}
	std::set<BaseCodeAttr,std::greater<BaseCodeAttr> > codes;
	GetBaseCode(result,_tcslen(lpTxt),codes);
	if(codes.size() == 1 && KeyHandler::CurrentKey != VK_BACK)
	{
		if(codes.begin()->IsChineseWord())
		{
			this->lpImmData->GetCompStrClass()->SetResultString(codes.begin()->GetCode());
			return 1;
		}
		else
		{
			this->lpImmData->GetCompStrClass()->PutCode(codes.begin()->GetCode());
			return this->TranslateInput();
		}
	}
	else if(codes.size() == 0)
		return 0;
	else
	{
		this->lpImmData->GetCandStrClass()->SetCandidateCount(codes.size());
		UINT index = 0;
		for(std::set<BaseCodeAttr,std::greater<BaseCodeAttr> >::iterator it = codes.begin(); it != codes.end(); ++it)
		{
			this->lpImmData->GetCandStrClass()->SetCandidateStr(it->GetCode(),it->IsChineseWord(),index++);			
		}
		return 2;
	}
	return 2;
}

UINT KnowledgeProcess::SelectTheFirst(BOOL directCodeInput)
{
	UINT ret = 0;
	if(directCodeInput)
	{
		preResult.clear();
		ret = this->TranslateInput();
		if(ret != 2)
			return ret;
	}
	do	
	{
		LPCANDSTRUCT p = this->lpImmData->GetCandStrClass()->GetCode(0);
		if(p)
		{
			if(p->isCompleteWord)
			{
				this->lpImmData->GetCompStrClass()->SetResultString(p->szCnadStr);
				return 1;
			}
			else
				this->lpImmData->GetCompStrClass()->PutCode(p->szCnadStr);
		}
	}
	while((ret = this->TranslateInput()) == 2);
	return ret;
}